{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PpxUjevvu6uF"
      },
      "source": [
        "## Initializations and imports"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "BRAn13fb-_Np"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from datetime import datetime\n",
        "import random"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oQUOaTsFAV4s"
      },
      "outputs": [],
      "source": [
        "from PIL import Image\n",
        "import numpy as np"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Q7ivyFJm0u7Q",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "d0f0ae0f-fb99-48c5-e1e0-347ccec0ac44"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Mounted at /content/drive\n"
          ]
        }
      ],
      "source": [
        "from google.colab import drive\n",
        "\n",
        "drive.mount(\"/content/drive\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MxfsPr1x1aLM"
      },
      "source": [
        "## Extracting the datasets with bpf 5"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4FLrJmFgxFtx"
      },
      "outputs": [],
      "source": [
        "def unzip_dataset(path, dataset_name):\n",
        "  # Extracting the .tar.zip file of dataset\n",
        "  ! tar -xzf $path\n",
        "\n",
        "  # Just chaning the name of extracted folder to dataset_name\n",
        "  dataset_name = f\"EKM_{dataset_name}_dataset\"\n",
        "  ! mv EKM_dataset $dataset_name\n",
        "\n",
        "  # Moving the train and test EKMs into one folder\n",
        "  train_source_path = f\"/content/{dataset_name}/train\"\n",
        "  dest = f\"/content/{dataset_name}\"\n",
        "\n",
        "  ! cd $train_source_path; ls | xargs realpath | xargs mv -t $dest\n",
        "  ! mv $dataset_name/test/* $dataset_name\n",
        "\n",
        "  ! rm -r $dataset_name/train\n",
        "  ! rm -r $dataset_name/test"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "-WY3hONzL9C3",
        "outputId": "ae5089c1-dc5b-4251-e2ac-065270de8aaa"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "total 33M\n",
            "drwx------ 2 root root 4.0K Aug 10 01:23 'N. Mokhtari'\n",
            "-rw------- 1 root root 3.5M Aug 10 09:09  EKM_PTBDB_5bpf.tar.gz\n",
            "-rw------- 1 root root 8.8M Aug 13 13:55  EKM_MIT_DB_5bpf.tar.gz\n",
            "-rw------- 1 root root  21M Aug 13 19:40  EKM_NSRDB_5bpf.tar.gz\n"
          ]
        }
      ],
      "source": [
        "! ls /content/drive/MyDrive/ECG\\ project/ -ltrh"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "08OjNR2xxvTS"
      },
      "outputs": [],
      "source": [
        "source_path = \"/content/drive/MyDrive/ECG\\ project\"\n",
        "\n",
        "nsrdb_path = f\"{source_path}/EKM_NSRDB_5bpf.tar.gz\"\n",
        "mitdb_path = f\"{source_path}/EKM_MIT_DB_5bpf.tar.gz\"\n",
        "ptbdb_path = f\"{source_path}/EKM_PTBDB_5bpf.tar.gz\"\n",
        "\n",
        "unzip_dataset(nsrdb_path, \"NSRDB\")\n",
        "unzip_dataset(mitdb_path, \"MITDB\")\n",
        "unzip_dataset(ptbdb_path, \"PTBDB\")"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Getting equal number of users from datasets"
      ],
      "metadata": {
        "id": "0ZMQAeL7U8w3"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "Getting minimun amount of users of all datasets, then getting same amount of users from datasets randomly."
      ],
      "metadata": {
        "id": "PeUdfBMcViq_"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# We know that NSRDB has 18 users,\n",
        "#              MITDB has 48 users,\n",
        "#              PTBDB has 290 users,\n",
        "# so we randomly select 18 users from MITDB and PTBDB users"
      ],
      "metadata": {
        "id": "iCOiwhPRVgI8"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "users_amount = 18"
      ],
      "metadata": {
        "id": "DtnuuHaVkotF"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "dataset_users_amount_dict = {\n",
        "    \"PTBDB\": 290,\n",
        "    \"MITDB\": 48,\n",
        "    \"NSRDB\": 18\n",
        "}"
      ],
      "metadata": {
        "id": "9wq53xQA0O5V"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "def users_list(dataset_path, dataset_name):\n",
        "  # Getting PTBDB's users' id\n",
        "  image_files = os.listdir(dataset_path)\n",
        "\n",
        "  dataset_users = []\n",
        "  for img_name in image_files:\n",
        "    user_id = img_name.split(\"-\")[-2]\n",
        "    if user_id not in dataset_users:\n",
        "      dataset_users.append(user_id)\n",
        "\n",
        "  # Checking the correctness\n",
        "  if (len(dataset_users) == dataset_users_amount_dict[dataset_name]):\n",
        "    print(f\"All good with {len(dataset_users)} users for \\\n",
        "    {dataset_name} dataset.\")\n",
        "  else:\n",
        "    print(f\"Well, amount of users is {len(dataset_users)} for \\\n",
        "    {dataset_name} dataset so somthing is wrong!\")\n",
        "\n",
        "  return dataset_users"
      ],
      "metadata": {
        "id": "Pb7kjHZIdaIz"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "ptbdb_users = users_list(\"/content/EKM_PTBDB_dataset\", \"PTBDB\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ILlgz-g86Jrd",
        "outputId": "c6e56eb3-6959-4316-8036-45e6f82192f2"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "All good with 290 users for     PTBDB dataset.\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "mitdb_users = users_list(\"/content/EKM_MITDB_dataset\", \"MITDB\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "kkQyTWof6w-T",
        "outputId": "e9cb404c-90b0-466b-ebb6-3898955eaa72"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "All good with 48 users for     MITDB dataset.\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "nsrdb_users = users_list(\"/content/EKM_NSRDB_dataset\", \"NSRDB\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "fZuvcPxfwvKk",
        "outputId": "f0f5cd7c-1552-4b70-fba2-59e88426a4cb"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "All good with 18 users for     NSRDB dataset.\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Getting required amount (users_amount) of users randomly for PTBDB\n",
        "ptbdb_random_users = random.sample(ptbdb_users, users_amount)"
      ],
      "metadata": {
        "id": "q5Tl32likkCF"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Getting required amount (users_amount) of users randomly for MITDB\n",
        "mitdb_random_users = random.sample(mitdb_users, users_amount)"
      ],
      "metadata": {
        "id": "soBAD7Bu67ys"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Getting average amount of EKMs for chosen users"
      ],
      "metadata": {
        "id": "cc2I_T7rWkWL"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Creating dict of counters for each randomly-chosen users\n",
        "# of NSRDB dataset\n",
        "# Also creating dict of users' EKMs\n",
        "NSRDB_users_EKM_amount_dict = {}\n",
        "NSRDB_users_EKMs_dict = {}\n",
        "\n",
        "for user in nsrdb_users:\n",
        "  NSRDB_users_EKM_amount_dict[user] = 0\n",
        "  NSRDB_users_EKMs_dict[user] = []"
      ],
      "metadata": {
        "id": "tTmdNkC_v0f8"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Counting each user's EKMs in dataset and collecting EKMs of him/her\n",
        "dataset_path = \"/content/EKM_NSRDB_dataset\"\n",
        "image_files = os.listdir(dataset_path)\n",
        "\n",
        "for img_name in image_files:\n",
        "    user_id = img_name.split(\"-\")[-2]\n",
        "    NSRDB_users_EKM_amount_dict[user_id] += 1\n",
        "    NSRDB_users_EKMs_dict[user_id].append(img_name)"
      ],
      "metadata": {
        "id": "I0LOwqD5w-mj"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "NSRDB_users_EKM_amount_dict"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Jc40GMR7oCV4",
        "outputId": "d35abbf7-059a-4702-e999-d309c46b506c"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "{'19140': 3000,\n",
              " '16483': 3000,\n",
              " '16795': 3000,\n",
              " '16273': 3000,\n",
              " '16265': 3000,\n",
              " '16420': 3000,\n",
              " '16786': 3000,\n",
              " '16539': 3000,\n",
              " '16773': 3000,\n",
              " '18184': 3000,\n",
              " '19830': 3000,\n",
              " '19090': 3000,\n",
              " '18177': 3000,\n",
              " '16272': 3000,\n",
              " '19093': 3000,\n",
              " '19088': 3000,\n",
              " '17453': 3000,\n",
              " '17052': 3000}"
            ]
          },
          "metadata": {},
          "execution_count": 18
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Creating dict of counters for each randomly-chosen users\n",
        "# of MITDB dataset\n",
        "# Also creating dict of users' EKMs\n",
        "MITDB_random_users_EKM_amount_dict = {}\n",
        "MITDB_random_users_EKMs_dict = {}\n",
        "\n",
        "for user in mitdb_random_users:\n",
        "  MITDB_random_users_EKM_amount_dict[user] = 0\n",
        "  MITDB_random_users_EKMs_dict[user] = []"
      ],
      "metadata": {
        "id": "z-nIiwhtfFLs"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Counting each user's EKMs in dataset and collecting EKMs of him/her\n",
        "dataset_path = \"/content/EKM_MITDB_dataset\"\n",
        "image_files = os.listdir(dataset_path)\n",
        "\n",
        "for img_name in image_files:\n",
        "    user_id = img_name.split(\"-\")[-2]\n",
        "    if user_id in mitdb_random_users:\n",
        "      MITDB_random_users_EKM_amount_dict[user_id] += 1\n",
        "      MITDB_random_users_EKMs_dict[user_id].append(img_name)"
      ],
      "metadata": {
        "id": "pa65EhuwfVda"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "MITDB_random_users_EKM_amount_dict"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "l2osBItFoFtJ",
        "outputId": "91dc7e73-9b91-4d59-9194-68d5d0f9f06e"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "{'210': 518,\n",
              " '124': 319,\n",
              " '223': 518,\n",
              " '222': 489,\n",
              " '100': 454,\n",
              " '221': 480,\n",
              " '121': 372,\n",
              " '107': 423,\n",
              " '205': 530,\n",
              " '112': 508,\n",
              " '213': 649,\n",
              " '118': 455,\n",
              " '220': 409,\n",
              " '103': 416,\n",
              " '104': 411,\n",
              " '102': 437,\n",
              " '209': 601,\n",
              " '230': 451}"
            ]
          },
          "metadata": {},
          "execution_count": 21
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "int(sum(MITDB_random_users_EKM_amount_dict.values()) / users_amount)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "J4kg6aV_fgR4",
        "outputId": "c67bd75e-7088-4fa7-8a2c-42bcee757369"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "468"
            ]
          },
          "metadata": {},
          "execution_count": 22
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Creating dict of counters for each randomly-chosen users\n",
        "# of PTBDB dataset\n",
        "# Also creating dict of users' EKMs\n",
        "ptbdb_random_users_EKM_amount_dict = {}\n",
        "ptbdb_random_users_EKMs_dict = {}\n",
        "\n",
        "for user in ptbdb_random_users:\n",
        "  ptbdb_random_users_EKM_amount_dict[user] = 0\n",
        "  ptbdb_random_users_EKMs_dict[user] = []"
      ],
      "metadata": {
        "id": "CHYHskexXgiD"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Counting each user's EKMs in dataset and collecting EKMs of him/her\n",
        "dataset_path = \"/content/EKM_PTBDB_dataset\"\n",
        "image_files = os.listdir(dataset_path)\n",
        "\n",
        "for img_name in image_files:\n",
        "    user_id = img_name.split(\"-\")[-2]\n",
        "    if user_id in ptbdb_random_users:\n",
        "      ptbdb_random_users_EKM_amount_dict[user_id] += 1\n",
        "      ptbdb_random_users_EKMs_dict[user_id].append(img_name)"
      ],
      "metadata": {
        "id": "UL2LoqaKWthV"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "ptbdb_random_users_EKM_amount_dict"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "iZJHAM9JoJaC",
        "outputId": "c7417ad9-d272-4f4b-d118-badb71c2f039"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "{'093': 56,\n",
              " '216': 27,\n",
              " '191': 25,\n",
              " '181': 14,\n",
              " '232': 36,\n",
              " '154': 6,\n",
              " '138': 11,\n",
              " '257': 31,\n",
              " '009': 9,\n",
              " '168': 14,\n",
              " '064': 34,\n",
              " '008': 33,\n",
              " '060': 33,\n",
              " '072': 49,\n",
              " '234': 21,\n",
              " '279': 32,\n",
              " '001': 45,\n",
              " '022': 37}"
            ]
          },
          "metadata": {},
          "execution_count": 25
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "average_EKMs_amount_each_user = int(sum(ptbdb_random_users_EKM_amount_dict.values()) / users_amount)\n",
        "average_EKMs_amount_each_user"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Q9qtsfI3ckNK",
        "outputId": "24e6adad-6226-49dd-8d36-5863e3f76d79"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "28"
            ]
          },
          "metadata": {},
          "execution_count": 26
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Getting random EKMs for each user in different datasets"
      ],
      "metadata": {
        "id": "G52r0Au7uJJ-"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "average_EKMs_amount_each_user = 20"
      ],
      "metadata": {
        "id": "PTOgxssaoP8_"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Getting random EKMs from NSRDB's users' EKMs\n",
        "NSRDB_EKMs = []\n",
        "for user in NSRDB_users_EKMs_dict.keys():\n",
        "  NSRDB_EKMs = NSRDB_EKMs + random.sample(NSRDB_users_EKMs_dict[user], \\\n",
        "                average_EKMs_amount_each_user)"
      ],
      "metadata": {
        "id": "3RTXJzj0yDFA"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Getting random EKMs from MITDB's users' EKMs\n",
        "# Note: we check if the user have enough EKMs (average amount) or not.\n",
        "# If a user doesn't have enough EKMs, we get all the available EKMs\n",
        "MITDB_EKMs = []\n",
        "for user in MITDB_random_users_EKMs_dict.keys():\n",
        "  if MITDB_random_users_EKM_amount_dict[user] < average_EKMs_amount_each_user:\n",
        "    MITDB_EKMs = MITDB_EKMs + MITDB_random_users_EKMs_dict[user]\n",
        "  else:\n",
        "    MITDB_EKMs = MITDB_EKMs + random.sample(MITDB_random_users_EKMs_dict[user], \\\n",
        "                average_EKMs_amount_each_user)"
      ],
      "metadata": {
        "id": "llRvoMdmzS6E"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Getting random EKMs from PTBDB's users' EKMs\n",
        "# Note: we check if the user have enough EKMs (average amount) or not.\n",
        "# If a user doesn't have enough EKMs, we get all the available EKMs\n",
        "PTBDB_EKMs = []\n",
        "for user in ptbdb_random_users_EKMs_dict.keys():\n",
        "  if ptbdb_random_users_EKM_amount_dict[user] < average_EKMs_amount_each_user:\n",
        "    PTBDB_EKMs = PTBDB_EKMs + ptbdb_random_users_EKMs_dict[user]\n",
        "  else:\n",
        "    PTBDB_EKMs = PTBDB_EKMs + random.sample(ptbdb_random_users_EKMs_dict[user], \\\n",
        "                average_EKMs_amount_each_user)"
      ],
      "metadata": {
        "id": "c86ofJcM14wp"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vkkzSm2CtbBj"
      },
      "source": [
        "## Vectorizing the images"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yPTYn3QOtbBl"
      },
      "outputs": [],
      "source": [
        "def vertorizing_png_imges(address):\n",
        "  # Load the PNG image\n",
        "  image = Image.open(address)\n",
        "\n",
        "  # Convert the image to RGB mode\n",
        "  image = image.convert('RGB')\n",
        "\n",
        "  # Resize the image to match the input size expected by the CNN\n",
        "  desired_width = 33\n",
        "  desired_height = 21\n",
        "  image = image.resize((desired_width, desired_height))\n",
        "\n",
        "  # Convert the image to a NumPy array\n",
        "  image_array = np.array(image)\n",
        "\n",
        "  # Reshape the array to match the input shape expected by the CNN\n",
        "  # image_array = image_array.reshape((1, desired_height, desired_width, 3))\n",
        "\n",
        "  # Normalize the array\n",
        "  image_array = image_array.astype('float32') / 255.0\n",
        "\n",
        "  return image_array"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VmzXlf3htbBn"
      },
      "outputs": [],
      "source": [
        "from IPython.display import clear_output\n",
        "\n",
        "def progress_bar(index, path):\n",
        "\n",
        "  bar_length = 50\n",
        "\n",
        "  total_length = len(os.listdir(path))\n",
        "\n",
        "  step = int(total_length / bar_length)\n",
        "  prgress = int(index / step)\n",
        "\n",
        "  # Clear the current cell's output\n",
        "  clear_output(wait=True)\n",
        "\n",
        "  print(\"[\", end=\"\")\n",
        "\n",
        "  [print(\"*\", end=\"\") for i in range(prgress)]\n",
        "  [print(\"-\", end=\"\") for i in range(bar_length - prgress)]\n",
        "  print(\"]\")\n",
        "  print(f\"{index}/{total_length}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hc4syish2M5n"
      },
      "source": [
        "### NSRDB verctorization"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2eFMJYWjWavo"
      },
      "outputs": [],
      "source": [
        "X_nsrdb_dataset = []\n",
        "y_nsrdb_dataset = []"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "EFlKzb4rBzmO",
        "outputId": "41647fb0-809a-4327-b869-c08579270805"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[*************************************************-]\n",
            "53617/54000\n",
            "This cell took 0 minutes and 24 seconds to run.\n"
          ]
        }
      ],
      "source": [
        "# X data for cnn network input\n",
        "base_path = \"/content/EKM_NSRDB_dataset/\"\n",
        "images_names = os.listdir(base_path)\n",
        "\n",
        "before_run_time = datetime.now()\n",
        "\n",
        "# Get X_nsrdb_dataset by vectorization\n",
        "# and y_nsrdb_dataset by user ids\n",
        "for index, img_name in enumerate(images_names):\n",
        "    # Vectorizing just the EKMs that are randomly been chosen\n",
        "    if img_name not in NSRDB_EKMs:\n",
        "      continue\n",
        "\n",
        "    img_vector = vertorizing_png_imges(base_path + img_name)\n",
        "    X_nsrdb_dataset.append(img_vector)\n",
        "\n",
        "    img_name = img_name.split(\"-\")\n",
        "    label = img_name[-2]\n",
        "    y_nsrdb_dataset.append(label)\n",
        "\n",
        "    progress_bar(index, base_path)\n",
        "\n",
        "after_run_time = datetime.now()\n",
        "diff = after_run_time - before_run_time\n",
        "print(f\"This cell took {int(diff.seconds / 60)} minutes \\\n",
        "and {diff.seconds} seconds to run.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MHt7cxx_C7V9"
      },
      "source": [
        "### MITDB verctorization"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dzwlXL56C7V_"
      },
      "outputs": [],
      "source": [
        "X_MITDB_dataset = []\n",
        "y_MITDB_dataset = []"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "8KBDPUhcC7WA",
        "outputId": "48b259dc-2736-4e02-fd37-e728e45eca4e"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[*************************************************-]\n",
            "21556/21613\n",
            "This cell took 0 minutes and 14 seconds to run.\n"
          ]
        }
      ],
      "source": [
        "# X data for cnn network input\n",
        "base_path = \"/content/EKM_MITDB_dataset/\"\n",
        "images_names = os.listdir(base_path)\n",
        "\n",
        "before_run_time = datetime.now()\n",
        "\n",
        "# Get X_MITDB_dataset by vectorization\n",
        "# and y_MITDB_dataset by user ids\n",
        "for index, img_name in enumerate(images_names):\n",
        "    # Vectorizing just the EKMs that are randomly been chosen\n",
        "    if img_name not in MITDB_EKMs:\n",
        "      continue\n",
        "\n",
        "    img_vector = vertorizing_png_imges(base_path + img_name)\n",
        "    X_MITDB_dataset.append(img_vector)\n",
        "\n",
        "    img_name = img_name.split(\"-\")\n",
        "    label = str(int(img_name[-2]) + 100)\n",
        "    y_MITDB_dataset.append(label)\n",
        "\n",
        "    progress_bar(index, base_path)\n",
        "\n",
        "after_run_time = datetime.now()\n",
        "diff = after_run_time - before_run_time\n",
        "print(f\"This cell took {int(diff.seconds / 60)} minutes \\\n",
        "and {diff.seconds} seconds to run.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d8_-ic_XD2-O"
      },
      "source": [
        "### PTBDB verctorization"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GUmusVcgD2-Q"
      },
      "outputs": [],
      "source": [
        "X_PTBDB_dataset = []\n",
        "y_PTBDB_dataset = []"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QyJdHcpaD2-R",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "9cd8ab52-ad40-4f86-ddd6-09b3f218a9ed"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[**************************************************]\n",
            "9294/9297\n",
            "This cell took 0 minutes and 9 secondsto run.\n"
          ]
        }
      ],
      "source": [
        "# X data for cnn network input\n",
        "base_path = \"/content/EKM_PTBDB_dataset/\"\n",
        "images_names = os.listdir(base_path)\n",
        "\n",
        "before_run_time = datetime.now()\n",
        "\n",
        "# Get X_PTBDB_dataset by vectorization\n",
        "# and y_PTBDB_dataset by user ids\n",
        "for index, img_name in enumerate(images_names):\n",
        "    # Vectorizing just the EKMs that are randomly been chosen\n",
        "    if img_name not in PTBDB_EKMs:\n",
        "      continue\n",
        "\n",
        "    img_vector = vertorizing_png_imges(base_path + img_name)\n",
        "    X_PTBDB_dataset.append(img_vector)\n",
        "\n",
        "    img_name = img_name.split(\"-\")\n",
        "    # ToDo (optional): 1000 can be replcaed with actual number of previous\n",
        "    # dataset's users\n",
        "    label = str(int(img_name[-2]) + 1000)\n",
        "    y_PTBDB_dataset.append(label)\n",
        "\n",
        "    progress_bar(index, base_path)\n",
        "\n",
        "after_run_time = datetime.now()\n",
        "diff = after_run_time - before_run_time\n",
        "print(f\"This cell took {int(diff.seconds / 60)} minutes \\\n",
        "and {diff.seconds} secondsto run.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Creating new dataset with equal users from each dataset and also with equal amount of EKMs for each user"
      ],
      "metadata": {
        "id": "2JUd6o0deb2x"
      }
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IdSBR8l3Ez6v"
      },
      "outputs": [],
      "source": [
        "X_mixed_dataset = []\n",
        "y_mixed_dataset = []"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MHydYuCfFFmk"
      },
      "outputs": [],
      "source": [
        "X_mixed_dataset.extend(X_nsrdb_dataset)\n",
        "X_mixed_dataset.extend(X_MITDB_dataset)\n",
        "X_mixed_dataset.extend(X_PTBDB_dataset)\n",
        "\n",
        "X_mixed_dataset = np.array(X_mixed_dataset)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "xVPOa96AFbWy"
      },
      "outputs": [],
      "source": [
        "y_mixed_dataset.extend(y_nsrdb_dataset)\n",
        "y_mixed_dataset.extend(y_MITDB_dataset)\n",
        "y_mixed_dataset.extend(y_PTBDB_dataset)\n",
        "\n",
        "y_mixed_dataset = np.array(y_mixed_dataset)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XjuucVVjGake"
      },
      "source": [
        "## CNN Architecture"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jRJb9-HYy-X0",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "1eb2ff7f-e9c0-413b-cad2-b97ad67b0f2f"
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "1034"
            ]
          },
          "metadata": {},
          "execution_count": 42
        }
      ],
      "source": [
        "len(X_mixed_dataset)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QvFaHj657pdO",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "60da88e0-6e54-40c6-e155-c4018b9439bf"
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "(21, 33, 3)"
            ]
          },
          "metadata": {},
          "execution_count": 43
        }
      ],
      "source": [
        "X_mixed_dataset[0].shape"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "j9AK5eJBPBcH"
      },
      "outputs": [],
      "source": [
        "def numerical_labels(labels_arr, dict_of_labels={}):\n",
        "  # This function change the labels of train and test\n",
        "  # data to numerical ones.\n",
        "  # Note: for the test data we should pass the train\n",
        "  # data labels\n",
        "\n",
        "  if dict_of_labels == {}:\n",
        "    unique_labels = np.unique(labels_arr)\n",
        "\n",
        "    for i, value in enumerate(unique_labels):\n",
        "        dict_of_labels[value] = i\n",
        "\n",
        "  # print(dict_of_labels)\n",
        "\n",
        "  num_lbls = []\n",
        "  for lbl in labels_arr:\n",
        "    num_lbls.append(dict_of_labels[lbl])\n",
        "\n",
        "  num_lbls = np.array(num_lbls)\n",
        "\n",
        "  return dict_of_labels, num_lbls"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VgV1ynABHUM_"
      },
      "outputs": [],
      "source": [
        "label_dict, numerical_y_mixed_labels = numerical_labels(y_mixed_dataset)"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "len(np.unique(numerical_y_mixed_labels))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "jzl-hUdKmJg4",
        "outputId": "b91a534c-a57b-41c1-c285-3b880a9c0593"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "54"
            ]
          },
          "metadata": {},
          "execution_count": 46
        }
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JjRWnXyXuvKA"
      },
      "outputs": [],
      "source": [
        "from sklearn.model_selection import train_test_split\n",
        "\n",
        "X_train, X_test, y_train, y_test = train_test_split(X_mixed_dataset, numerical_y_mixed_labels, test_size=0.2, random_state=42)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FAUdHRLox-Ke"
      },
      "outputs": [],
      "source": [
        "from tensorflow.keras.models import Sequential\n",
        "from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout\n",
        "from tensorflow.keras.optimizers import Adam"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "T-P9sACYVBMD"
      },
      "outputs": [],
      "source": [
        "# Creating the CNN model\n",
        "model = Sequential([\n",
        "    Conv2D(32, (3, 3), activation='relu', input_shape=(21, 33, 3)),\n",
        "    MaxPooling2D(pool_size=(2, 2)),\n",
        "    Dropout(0.7),\n",
        "    Flatten(),\n",
        "    Dense(128, activation='relu'),\n",
        "    Dense(64, activation='relu'),\n",
        "    Dense(54, activation='softmax')\n",
        "])\n",
        "\n",
        "# Setting Adam optimizer\n",
        "optimizer = Adam(learning_rate=0.001)\n",
        "\n",
        "# Compileing the model with the optimizer\n",
        "model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "o-xquUYwMUxN",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "41034819-0d5d-4f9a-ffe7-5ea2b59af01b"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Epoch 1/80\n",
            "26/26 [==============================] - 2s 22ms/step - loss: 3.9865 - accuracy: 0.0314\n",
            "Epoch 2/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 3.7896 - accuracy: 0.0822\n",
            "Epoch 3/80\n",
            "26/26 [==============================] - 1s 22ms/step - loss: 3.2865 - accuracy: 0.1983\n",
            "Epoch 4/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 2.5580 - accuracy: 0.3120\n",
            "Epoch 5/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 2.0360 - accuracy: 0.4268\n",
            "Epoch 6/80\n",
            "26/26 [==============================] - 1s 22ms/step - loss: 1.6698 - accuracy: 0.5224\n",
            "Epoch 7/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 1.3742 - accuracy: 0.5973\n",
            "Epoch 8/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 1.1818 - accuracy: 0.6324\n",
            "Epoch 9/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 1.0642 - accuracy: 0.6530\n",
            "Epoch 10/80\n",
            "26/26 [==============================] - 1s 22ms/step - loss: 0.8464 - accuracy: 0.7570\n",
            "Epoch 11/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.7650 - accuracy: 0.7618\n",
            "Epoch 12/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.6464 - accuracy: 0.8005\n",
            "Epoch 13/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.5670 - accuracy: 0.8343\n",
            "Epoch 14/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.4591 - accuracy: 0.8875\n",
            "Epoch 15/80\n",
            "26/26 [==============================] - 1s 23ms/step - loss: 0.4527 - accuracy: 0.8670\n",
            "Epoch 16/80\n",
            "26/26 [==============================] - 1s 35ms/step - loss: 0.4027 - accuracy: 0.8948\n",
            "Epoch 17/80\n",
            "26/26 [==============================] - 1s 36ms/step - loss: 0.3568 - accuracy: 0.9008\n",
            "Epoch 18/80\n",
            "26/26 [==============================] - 1s 37ms/step - loss: 0.3302 - accuracy: 0.9057\n",
            "Epoch 19/80\n",
            "26/26 [==============================] - 1s 36ms/step - loss: 0.3164 - accuracy: 0.9154\n",
            "Epoch 20/80\n",
            "26/26 [==============================] - 1s 36ms/step - loss: 0.2401 - accuracy: 0.9323\n",
            "Epoch 21/80\n",
            "26/26 [==============================] - 1s 23ms/step - loss: 0.2552 - accuracy: 0.9250\n",
            "Epoch 22/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.2466 - accuracy: 0.9335\n",
            "Epoch 23/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.2195 - accuracy: 0.9347\n",
            "Epoch 24/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 0.1915 - accuracy: 0.9468\n",
            "Epoch 25/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.1860 - accuracy: 0.9444\n",
            "Epoch 26/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.1746 - accuracy: 0.9432\n",
            "Epoch 27/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.1502 - accuracy: 0.9637\n",
            "Epoch 28/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.1474 - accuracy: 0.9625\n",
            "Epoch 29/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.1472 - accuracy: 0.9625\n",
            "Epoch 30/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 0.1305 - accuracy: 0.9649\n",
            "Epoch 31/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.1349 - accuracy: 0.9613\n",
            "Epoch 32/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.1350 - accuracy: 0.9553\n",
            "Epoch 33/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 0.1011 - accuracy: 0.9758\n",
            "Epoch 34/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.1316 - accuracy: 0.9625\n",
            "Epoch 35/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.1373 - accuracy: 0.9541\n",
            "Epoch 36/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.1420 - accuracy: 0.9492\n",
            "Epoch 37/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0887 - accuracy: 0.9794\n",
            "Epoch 38/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0761 - accuracy: 0.9843\n",
            "Epoch 39/80\n",
            "26/26 [==============================] - 1s 29ms/step - loss: 0.0942 - accuracy: 0.9686\n",
            "Epoch 40/80\n",
            "26/26 [==============================] - 1s 36ms/step - loss: 0.0711 - accuracy: 0.9903\n",
            "Epoch 41/80\n",
            "26/26 [==============================] - 1s 35ms/step - loss: 0.0598 - accuracy: 0.9891\n",
            "Epoch 42/80\n",
            "26/26 [==============================] - 1s 35ms/step - loss: 0.0628 - accuracy: 0.9879\n",
            "Epoch 43/80\n",
            "26/26 [==============================] - 1s 37ms/step - loss: 0.0828 - accuracy: 0.9782\n",
            "Epoch 44/80\n",
            "26/26 [==============================] - 1s 33ms/step - loss: 0.0914 - accuracy: 0.9770\n",
            "Epoch 45/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 0.0644 - accuracy: 0.9879\n",
            "Epoch 46/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0647 - accuracy: 0.9891\n",
            "Epoch 47/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 0.0516 - accuracy: 0.9831\n",
            "Epoch 48/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0533 - accuracy: 0.9879\n",
            "Epoch 49/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 0.0631 - accuracy: 0.9831\n",
            "Epoch 50/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0770 - accuracy: 0.9770\n",
            "Epoch 51/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0611 - accuracy: 0.9807\n",
            "Epoch 52/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 0.0655 - accuracy: 0.9843\n",
            "Epoch 53/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0444 - accuracy: 0.9891\n",
            "Epoch 54/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 0.0556 - accuracy: 0.9855\n",
            "Epoch 55/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0586 - accuracy: 0.9867\n",
            "Epoch 56/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 0.0512 - accuracy: 0.9891\n",
            "Epoch 57/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0694 - accuracy: 0.9782\n",
            "Epoch 58/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0972 - accuracy: 0.9686\n",
            "Epoch 59/80\n",
            "26/26 [==============================] - 1s 22ms/step - loss: 0.0620 - accuracy: 0.9782\n",
            "Epoch 60/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0594 - accuracy: 0.9855\n",
            "Epoch 61/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0389 - accuracy: 0.9940\n",
            "Epoch 62/80\n",
            "26/26 [==============================] - 1s 20ms/step - loss: 0.0413 - accuracy: 0.9915\n",
            "Epoch 63/80\n",
            "26/26 [==============================] - 1s 34ms/step - loss: 0.0485 - accuracy: 0.9903\n",
            "Epoch 64/80\n",
            "26/26 [==============================] - 1s 36ms/step - loss: 0.0450 - accuracy: 0.9867\n",
            "Epoch 65/80\n",
            "26/26 [==============================] - 1s 37ms/step - loss: 0.0363 - accuracy: 0.9903\n",
            "Epoch 66/80\n",
            "26/26 [==============================] - 1s 36ms/step - loss: 0.0380 - accuracy: 0.9891\n",
            "Epoch 67/80\n",
            "26/26 [==============================] - 1s 37ms/step - loss: 0.0290 - accuracy: 0.9940\n",
            "Epoch 68/80\n",
            "26/26 [==============================] - 1s 28ms/step - loss: 0.0347 - accuracy: 0.9940\n",
            "Epoch 69/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0382 - accuracy: 0.9915\n",
            "Epoch 70/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0223 - accuracy: 0.9964\n",
            "Epoch 71/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0255 - accuracy: 0.9940\n",
            "Epoch 72/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0381 - accuracy: 0.9903\n",
            "Epoch 73/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0446 - accuracy: 0.9867\n",
            "Epoch 74/80\n",
            "26/26 [==============================] - 1s 22ms/step - loss: 0.0338 - accuracy: 0.9891\n",
            "Epoch 75/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0665 - accuracy: 0.9819\n",
            "Epoch 76/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0416 - accuracy: 0.9867\n",
            "Epoch 77/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0420 - accuracy: 0.9879\n",
            "Epoch 78/80\n",
            "26/26 [==============================] - 1s 22ms/step - loss: 0.0485 - accuracy: 0.9855\n",
            "Epoch 79/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0400 - accuracy: 0.9879\n",
            "Epoch 80/80\n",
            "26/26 [==============================] - 1s 21ms/step - loss: 0.0365 - accuracy: 0.9867\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "<keras.callbacks.History at 0x7e6bf83d9f00>"
            ]
          },
          "metadata": {},
          "execution_count": 50
        }
      ],
      "source": [
        "# Train the model\n",
        "model.fit(X_train, y_train, epochs=80, batch_size=32)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sc36-Oqn6MY3",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "bae5cc81-0ead-4b23-ec27-d0127b2e4a1f"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "7/7 - 0s - loss: 0.3828 - accuracy: 0.9275 - 208ms/epoch - 30ms/step\n",
            "Test Loss: 0.3828\n",
            "Test Accuracy: 0.9275\n"
          ]
        }
      ],
      "source": [
        "# Evaluate the model on the unfair test set\n",
        "test_loss, test_accuracy = model.evaluate(X_test, y_test, verbose=2)\n",
        "print(f'Test Loss: {test_loss:.4f}')\n",
        "print(f'Test Accuracy: {test_accuracy:.4f}')"
      ]
    }
  ]
}